package com.sec.android.app.myfiles.util;

import android.app.Activity;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;

import com.sec.android.app.myfiles.MyFilesTestRunner;
import com.sec.android.app.myfiles.TestInput;
import com.sec.android.app.myfiles.info.AppConstants;
import com.sec.android.app.myfiles.info.MimeType;
import com.sec.android.app.myfiles.mockclass.ActivityMock;
import com.sec.android.app.myfiles.mockclass.CursorMock;
import com.sec.android.app.myfiles.module.abstraction.FileRecord;
import com.sec.android.app.myfiles.module.local.file.LocalFileRecord;
import com.sec.android.app.myfiles.shadow.android.ShadowContentResolver;
import com.sec.android.app.myfiles.shadow.android.ShadowStorageManager;
import com.sec.android.app.myfiles.shadow.sem.ShadowSemPersonaManager;
import com.sec.android.app.myfiles.shadow.sem.ShadowSemPrivateModeManager;

import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.robolectric.RuntimeEnvironment;

import java.util.ArrayList;

import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;


@RunWith(MyFilesTestRunner.class)
public class testFileUtils {
    Context mContext;

    @Before
    public void setUp() throws Exception {
        ShadowSemPersonaManager.init();
        ShadowSemPrivateModeManager.init();
        mContext = RuntimeEnvironment.application;
    }

    @After
    public void tearDown() throws Exception {
        ShadowStorageManager.clearStorageVolumes();
    }

    @Test
    public void testIsUnderPath() {
        TestInput<Boolean>[] testList = TestInput.createTestData(
                new TestInput<>(true, "/test", "/test"),
                new TestInput<>(false, "/test", "/testName"),
                new TestInput<>(true, "/test", "/test/Name"),
                new TestInput<>(true, "/test", "/test/Name/test"),
                new TestInput<>(false, "/test", "./test/Name/test"),
                new TestInput<>(false, null, "/test"),
                new TestInput<>(false, "/test", null),
                new TestInput<>(false, null, null));


        for (TestInput<Boolean> testData : testList) {
            Boolean actual = FileUtils.isUnderPath((String) testData.get(0), (String) testData.get(1));
            Assert.assertEquals(testData.expected(), actual);
        }
    }

    @Test
    public void isSdMemoryPath() {
        TestInput<Boolean>[] testList = TestInput.createTestData(
                new TestInput<>(true, "/test", "/test"),
                new TestInput<>(false, "/test", "/testName"),
                new TestInput<>(true, "/test", "/test/Name"),
                new TestInput<>(true, "/test", "/test/Name/test"),
                new TestInput<>(false, "/test", "./test/Name/test"));

        for (TestInput<Boolean> testData : testList) {
            Boolean actual = FileUtils.isUnderPath((String) testData.get(0), (String) testData.get(1));
            Assert.assertEquals(testData.expected(), actual);
        }
    }

    @Test
    public void testIsPrivateFolder() {
        TestInput[] testList = TestInput.createTestData(
                new TestInput<>(true, AppConstants.StoragePath.PRIVATE_ROOT),
                new TestInput<>(true, AppConstants.StoragePath.PRIVATE_ROOT + "/test"),
                new TestInput<>(false, AppConstants.StoragePath.PRIVATE_ROOT + "test"),
                new TestInput<>(false, AppConstants.StoragePath.INTERNAL_ROOT + "test"));

        for (TestInput testData : testList) {
            boolean actual = FileUtils.isPrivateFolder((String) testData.get(0));
            Assert.assertEquals((String) testData.get(0), testData.expected(), actual);
        }
    }

    @Test
    public void testIsNoneGoogleDocs() {
        String testMimeType = MimeType.DEFAULT;
        Assert.assertFalse(FileUtils.isGoogleDocs(testMimeType));
    }

    @Test
    public void testIsGoogleDocs() {
        String testMimeTypeList[] = {
                MimeType.GOOGLE_DOCS,
                MimeType.GOOGLE_SLIDES,
                MimeType.GOOGLE_SHEETS,
                MimeType.GOOGLE_DRAWING};

        for (String mimeType : testMimeTypeList) {
            Assert.assertTrue(FileUtils.isGoogleDocs(mimeType));
        }
        Assert.assertFalse(FileUtils.isGoogleDocs(MimeType.TEXT_FILE));
        Assert.assertFalse(FileUtils.isGoogleDocs(null));

    }

    @Test
    public void testIsNoPrivateFolder() {
        String path = "/TestRoot/test";
        Assert.assertFalse(FileUtils.isPrivateFolder(path));
    }

    @Test
    public void testisSystemFolderSystem() {
        String systemPathList[] = {
                "/system",
                "/sys",
                "/proc",
                "/storage/sdcard0",
                "/storage/emulated/legacy",
                "/storage/container"
        };

        for (String path : systemPathList) {
            Assert.assertTrue(FileUtils.isSystemFolder(path));
        }
    }

    @Test
    public void testUpdateRecentFile() {
        ArgumentCaptor<Uri> uri = ArgumentCaptor.forClass(Uri.class);
        ArgumentCaptor<ContentValues> contentValue = ArgumentCaptor.forClass(ContentValues.class);


        Activity activity = mock(Activity.class);
        ContentResolver contentResolver = mock(ContentResolver.class);
        when(activity.getContentResolver()).thenReturn(contentResolver);
        when(contentResolver.insert(uri.capture(), contentValue.capture())).thenReturn(null);

        FileRecord record = new LocalFileRecord(AppConstants.StoragePath.INTERNAL_ROOT + "/test.txt");
        FileUtils.updateRecentFile(activity, record);

        Uri actualUri = uri.getValue();
        ContentValues actualContentValues = contentValue.getValue();

        Assert.assertNotNull(actualUri);
        Assert.assertNotNull(actualContentValues);
        Assert.assertEquals("content://myfiles/recent_files", actualUri.toString());
        Assert.assertEquals(AppConstants.StoragePath.INTERNAL_ROOT, actualContentValues.get("_data"));
        Assert.assertEquals("test.txt", actualContentValues.get("name"));
    }

    @Test
    public void testOpenGoogleDocsFile() {
        String googleDocsLink = null;
        Activity activity = ActivityMock.createMock();
        FileUtils.openGoogleDocsFile(null, activity);

        Intent intent = ActivityMock.getStartActivityIntent();
        Assert.assertNull(intent);

        FileUtils.openGoogleDocsFile("hello", activity);
        intent = ActivityMock.getStartActivityIntent();
        Assert.assertNotNull(intent);

        ComponentName componentName = intent.getComponent();
        Assert.assertNotNull(componentName);
        Assert.assertEquals("com.google.android.apps.docs", componentName.getPackageName());
        Assert.assertEquals("com.google.android.apps.docs.openurl.OpenUrlActivity", componentName.getClassName());

        Uri uri = intent.getData();
        Assert.assertNotNull(uri);
        Assert.assertEquals("hello", uri.toString());
    }


    @Test
    public void testGetRecordType() {
        ArrayList<FileRecord> records = new ArrayList<>();
        records.add(new LocalFileRecord(AppConstants.StoragePath.INTERNAL_ROOT + "/test_file1.txt"));
        records.add(new LocalFileRecord(AppConstants.StoragePath.INTERNAL_ROOT + "/test_file2.txt"));
        Assert.assertEquals(FileUtils.ITEM_TYPE.FILE, FileUtils.getRecordType(records));

        records.add(new LocalFileRecord(AppConstants.StoragePath.INTERNAL_ROOT + "/test_Dir.txt"));
        records.add(new LocalFileRecord(AppConstants.StoragePath.INTERNAL_ROOT + "/test_Dir2.txt"));
        Assert.assertEquals(FileUtils.ITEM_TYPE.FILE_AND_FOLDER, FileUtils.getRecordType(records));

        records.clear();
        records.add(new LocalFileRecord(AppConstants.StoragePath.INTERNAL_ROOT + "/test_Dir.txt"));
        records.add(new LocalFileRecord(AppConstants.StoragePath.INTERNAL_ROOT + "/test_Dir2.txt"));
        Assert.assertEquals(FileUtils.ITEM_TYPE.FOLDER, FileUtils.getRecordType(records));
    }

    @Test
    public void testHasPrivateFile() {
        ArrayList<FileRecord> records = new ArrayList<>();
        records.add(new LocalFileRecord(AppConstants.StoragePath.INTERNAL_ROOT + "/test_file1.txt"));
        records.add(new LocalFileRecord(AppConstants.StoragePath.INTERNAL_ROOT + "/test_file2.txt"));
        Assert.assertFalse(FileUtils.hasPrivateFile(records));

        records.add(new LocalFileRecord(AppConstants.StoragePath.PRIVATE_ROOT + "/test_file2.txt"));
        Assert.assertTrue(FileUtils.hasPrivateFile(records));
    }


    @Test
    public void testIsSameAsRealFile() {
        FileRecord record = new LocalFileRecord(AppConstants.StoragePath.INTERNAL_ROOT + "/test.txt");
        boolean actual = FileUtils.isSameAsRealFile(record);
        Assert.assertTrue(actual);

        record = new LocalFileRecord(AppConstants.StoragePath.INTERNAL_ROOT + "/dst_test.txt");
        actual = FileUtils.isSameAsRealFile(record);
        Assert.assertFalse(actual);
    }


    @Test
    public void testIsNoMediaFile() {
        TestInput<Boolean>[] testList = TestInput.createTestData(
                //TRUE CASE
                new TestInput<>(true, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/._testFile"),
                new TestInput<>(true, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/AlbumArt_{aaa}.Jpg"),
                new TestInput<>(true, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/AlbumArt_{aaa, bbb, ccc}.jPg"),
                new TestInput<>(true, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/AlbumArt.aaa.ccc.jpG"),
                new TestInput<>(true, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/AlbumArtSmall.Jpg"),
                new TestInput<>(true, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/Folder.jPg"),
                new TestInput<>(true, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/ALBUMart_{aaa}.Jpg"),
                new TestInput<>(true, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/albumARTSMall.Jpg"),
                new TestInput<>(true, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/fOLDER.jPg"),

                //FALSE CASE
                new TestInput<>(false, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/data.jpg"),
                new TestInput<>(false, AppConstants.StoragePath.INTERNAL_ROOT + "/._dir/myDir"),
                new TestInput<>(false, AppConstants.StoragePath.INTERNAL_ROOT + "/._dir/testFile"),
                new TestInput<>(false, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/test._testFile"),
                new TestInput<>(false, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/AlbumArtSmall0.jpg"),
                new TestInput<>(false, AppConstants.StoragePath.INTERNAL_ROOT + "/dir/Folder0.jpg"));


        for (TestInput<Boolean> testData : testList) {
            Boolean actual = FileUtils.isNoMediaFile((String) testData.get(0));
            Assert.assertEquals((String) testData.get(0), testData.expected(), actual);
        }
    }

    @Test
    public void testGetMediaUri() {
        final int TEST_ID = 78;
        String path = AppConstants.StoragePath.INTERNAL_ROOT + "/data/Test";
        String expected = null;

        ShadowContentResolver.setCursor(CursorMock.createCursor(0));
        Uri actual = FileUtils.getMediaUri(mContext, FileUtils.MEDIA_PROVIDER_URI, path);
        Assert.assertNull(actual);


        ShadowContentResolver.setCursor(createCursorMockForMediaUri(TEST_ID, path));
        expected = FileUtils.MEDIA_PROVIDER_URI.toString() + "/" + TEST_ID;
        actual = FileUtils.getMediaUri(mContext, FileUtils.MEDIA_PROVIDER_URI, path);
        Assert.assertNotNull(actual);
        Assert.assertEquals(expected, actual.toString());
    }

    private Cursor createCursorMockForMediaUri(int id, String path) {
        Cursor cursorMock = CursorMock.createCursor(1);
        CursorMock.addColumnIndex(cursorMock, MediaStore.MediaColumns._ID, 0);
        CursorMock.addColumnIndex(cursorMock, MediaStore.MediaColumns.DATA, 1);
        CursorMock.addLongValue(cursorMock, 0, id);
        CursorMock.addStringValue(cursorMock, 1, path);

        return cursorMock;
    }


    @Test
    public void testGetUriByPath() {
        int TEST_ID = 99;

        TestInput<Integer>[] testList = TestInput.createTestData(
                new TestInput<Integer>(TEST_ID++, "/image/image.jpg", MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString()),
                new TestInput<Integer>(TEST_ID++, "/audio/audio.mp3", MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString()));

        for (TestInput<Integer> testData : testList) {
            ShadowContentResolver.setCursor(createCursorMockForMediaUri(testData.expected(), (String) testData.get(0)));
            Uri actual = FileUtils.getUriByPath(mContext, (String) testData.get(0));
            Uri expected = UiUtils.addUserIdToUri(Uri.parse((String) testData.get(1) + "/" + testData.expected()));
            Assert.assertEquals(expected, actual);
        }
    }

}

